use crate::error::Error;
use crate::events::EventSystem;
use crate::types::NodeInfo;
use anyhow::Result;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;

/// Storage manager that handles storage operations
pub struct StorageManager {
    state_machine: Arc<RwLock<ClusterStateMachine>>,
}

impl StorageManager {
    /// 创建新的存储管理器（目前仅内存状态机，占位实现）
    pub async fn new(_database_path: Option<&str>) -> Result<Self> {
        let state_machine = ClusterStateMachine::new();

        Ok(Self {
            state_machine: Arc::new(RwLock::new(state_machine)),
        })
    }

    /// 创建纯内存存储（快捷调用）
    pub async fn new_memory() -> Result<Self> {
        Self::new(None).await
    }

    /// 创建 DuckDB 存储（占位，尚未真正连接 DB）
    pub async fn new_duckdb(path: &str) -> Result<Self> {
        // Future: initialize DuckDB connection at path
        let _ = path;
        Self::new(Some(path)).await
    }

    /// 获取内部状态机引用 (Arc<RwLock<...>>)
    pub async fn get_state_machine(&self) -> Arc<RwLock<ClusterStateMachine>> {
        self.state_machine.clone()
    }

    /// 创建 Raft 日志存储（占位）
    pub async fn create_log_store(&self) -> Result<(), Error> {
        // Placeholder for now
        Ok(())
    }

    /// 创建 Raft 状态机（占位）
    pub async fn create_state_machine(&self, _event_system: Arc<EventSystem>) -> Result<(), Error> {
        // Placeholder for now
        Ok(())
    }
}

/// Cluster state machine that maintains the cluster state
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ClusterStateMachine {
    /// Map of node ID to node information
    pub nodes: HashMap<String, NodeInfo>,
    /// Cluster configuration
    pub config: HashMap<String, serde_json::Value>,
    /// Last applied log index
    pub last_applied: Option<u64>,
}

impl ClusterStateMachine {
    /// 创建新的空状态机
    pub fn new() -> Self {
        Self {
            nodes: HashMap::new(),
            config: HashMap::new(),
            last_applied: None,
        }
    }

    /// 应用一条 Raft 请求到状态机（根据请求类型修改内部结构）
    pub async fn apply_request(
        &mut self,
        request: &crate::raft::Request,
    ) -> Result<crate::raft::Response> {
        match request {
            crate::raft::Request::AddManagedNode { node } => {
                // Convert ManagedNode to NodeInfo (this is a simplification)
                let now = std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .unwrap_or_default()
                    .as_secs();
                let node_info = NodeInfo {
                    id: node.id.clone(),
                    address: node.address.clone(),
                    status: crate::types::NodeStatus::Active,
                    metadata: HashMap::new(),
                    last_seen: now,
                    joined_at: now,
                };
                self.nodes.insert(node.id.clone(), node_info);
                Ok(crate::raft::Response::Success)
            }
            crate::raft::Request::RemoveManagedNode { node_id } => {
                if self.nodes.remove(node_id).is_some() {
                    Ok(crate::raft::Response::Success)
                } else {
                    Ok(crate::raft::Response::Error {
                        message: format!("Node {} not found", node_id),
                    })
                }
            }
            crate::raft::Request::UpdateNodeStatus { node_id, status } => {
                if let Some(node) = self.nodes.get_mut(node_id) {
                    // Parse status string to NodeStatus enum
                    match status.as_str() {
                        "active" => node.status = crate::types::NodeStatus::Active,
                        "inactive" => node.status = crate::types::NodeStatus::Inactive,
                        "down" => node.status = crate::types::NodeStatus::Down,
                        "maintenance" => node.status = crate::types::NodeStatus::Maintenance,
                        _ => {
                            return Ok(crate::raft::Response::Error {
                                message: format!("Invalid status: {}", status),
                            })
                        }
                    }
                    node.last_seen = std::time::SystemTime::now()
                        .duration_since(std::time::UNIX_EPOCH)
                        .unwrap_or_default()
                        .as_secs();
                    Ok(crate::raft::Response::Success)
                } else {
                    Ok(crate::raft::Response::Error {
                        message: format!("Node {} not found", node_id),
                    })
                }
            }
            crate::raft::Request::UpdateConfiguration { config } => {
                if let Ok(config_map) =
                    serde_json::from_value::<HashMap<String, serde_json::Value>>(config.clone())
                {
                    self.config.extend(config_map);
                    Ok(crate::raft::Response::Success)
                } else {
                    Ok(crate::raft::Response::Error {
                        message: "Invalid configuration format".to_string(),
                    })
                }
            }
        }
    }

    /// 获取全部节点映射引用
    pub fn get_nodes(&self) -> &HashMap<String, NodeInfo> {
        &self.nodes
    }

    /// 根据 ID 获取单节点（不可变引用）
    pub fn get_node(&self, id: &str) -> Option<&NodeInfo> {
        self.nodes.get(id)
    }

    /// 获取集群配置映射
    pub fn get_config(&self) -> &HashMap<String, serde_json::Value> {
        &self.config
    }

    /// 统计处于 Active 状态的节点数量
    pub fn active_node_count(&self) -> usize {
        self.nodes
            .values()
            .filter(|node| matches!(node.status, crate::types::NodeStatus::Active))
            .count()
    }

    /// 统计健康节点数量（当前与 active 同义，可根据语义扩展）
    pub fn healthy_node_count(&self) -> usize {
        self.nodes
            .values()
            .filter(|node| matches!(node.status, crate::types::NodeStatus::Active))
            .count()
    }
}

impl Default for ClusterStateMachine {
    fn default() -> Self {
        Self::new()
    }
}
